﻿using Org.LyrcsoftFramework.Cloud.Core;
using Org.LyrcsoftFramework.Cloud.OpenFeign;
using Org.LyrcsoftFramework.Cloud.OpenFeign.Attributes;
using Org.LyrcsoftFramework.Cloud.Feign;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Nacos.V2;
using System.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Nacos.V2.Naming;
using Nacos.V2.Naming.Dtos;
using System.Runtime.InteropServices;
using Org.LyrcsoftFramework.Cloud.Core.Common;

namespace Org.LyrcsoftFramework.Cloud.Extensions
{
    /// <summary>
    /// MyFeign启动扩展
    /// </summary>
    public static class MyFeignBootExtentions
    {
        private static Boolean isBootstrap = false;

        /// <summary>
        /// 初始化启动
        /// </summary>
        public static void Bootstrap()
        {
            ServiceFactory.RegisterService<OpenFeign.IHttpClientFactory>(new DefaultHttpClientFactory());
            // 注入实际执行http请求的客户端
            ServiceFactory.RegisterService<IClient>(new IClient.DefaultFeignClient());
            ServiceFactory.RegisterService<IFeignEncoder>(new IFeignEncoder.DefaultEncoder());
            ServiceFactory.RegisterService<IFeignDecoder>(new IFeignDecoder.DefaultDecoder());
            ServiceFactory.RegisterService<HttpService>(new HttpService());
            ServiceFactory.RegisterService<DefaultRequestInterceptor>(new DefaultRequestInterceptor());
            isBootstrap = true;
        }
        /// <summary>
        /// 将服务注册到Nacos中
        /// </summary>
        public static async void AddNacos()
        {
            if (!isBootstrap)
            {
                Bootstrap();
            }
            String ServerAddresses = ConfigurationManager.AppSettings["Nacos:ServerAddresses"];
            String Namespace = ConfigurationManager.AppSettings["Nacos:Namespace"];
            String DataId = ConfigurationManager.AppSettings["Nacos:DataId"];
            String Group = ConfigurationManager.AppSettings["Nacos:Group"];
            String ServiceName = ConfigurationManager.AppSettings["Nacos:ServiceName"];
            String ServiceIp = ConfigurationManager.AppSettings["Nacos:ServiceIp"];
            Int32 ServicePort = Int32.Parse(ConfigurationManager.AppSettings["Nacos:ServicePort"]);

            NacosSdkOptions nacosOptions = new NacosSdkOptions
            {
                ServerAddresses = new List<string> { ServerAddresses },
                Namespace = Namespace
            };
            // 创建日志工厂
            var loggerFactory = new LoggerFactory();
            // 创建 NacosNamingService 实例
            NacosNamingService namingService = new NacosNamingService(loggerFactory, Options.Create(nacosOptions));
            ServiceFactory.RegisterService<NacosNamingService>(namingService);
            // 注册服务
            await namingService.RegisterInstance(ServiceName, Group, ServiceIp, ServicePort);
        }

        /// <summary>
        /// 将程序集中的申明了FeignClient的接口注入到程序上下文
        /// </summary>
        public static void AddMyFeignBoot(Action<FeignOption> action = null)
        {
            if (!isBootstrap)
            {
                Bootstrap();
            }
            // 
            var feignOption = new FeignOption();
            if (action != null)
            {
                action(feignOption);
            }
            // 注入HttpClient 默认工厂对象
            ServiceFactory.RegisterService<FeignOption>(feignOption);
            var feignProxyBuilder = new IFeignProxyBuilder.FeignProxyBuilder();
            ServiceFactory.RegisterService<IFeignProxyBuilder>(feignProxyBuilder);
            // 存储扫描到的所有接口
            var feignTypes = new List<Type>();
            var allAssemblies = ConfigureDependencyExtentions.GetAssemblies();
            foreach (var assembly in allAssemblies)
            {
                feignTypes.AddRange(assembly.GetExportedTypes().Where(it => it.IsInterface && it.GetCustomAttribute<FeignClientAttribute>() != null).ToList());
            }
            // 为扫描到的接口构建实现对象
            foreach (var type in feignTypes)
            {
                feignProxyBuilder.InitInterface(type);
                AddMyFeignBootService(type);
            }

        }

        /// <summary>
        /// 为每一个请求构建一个HttpClient
        /// </summary>
        private static void AddMyFeignBootService(Type serviceType)
        {
            if (!serviceType.IsInterface) throw new ArgumentException(nameof(serviceType));
            object Factory()
            {
                var feignProxyBuilder = ServiceFactory.GetService<IFeignProxyBuilder>();
                var httpService = ServiceFactory.GetService<HttpService>();
                var proxy = feignProxyBuilder.Build(serviceType, httpService);
                return proxy;
            };
            var feignClient = serviceType.GetCustomAttribute<FeignClientAttribute>();
            if (feignClient == null)
            {
                throw new ArgumentNullException(nameof(serviceType));
            }
            //判断方法返回类型是不是task<>
            foreach (var methodInfo in serviceType.GetMethods())
            {
                if (!typeof(Task<>).IsAssignableFrom(methodInfo.ReturnType) && !typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
                {
                    throw new ArgumentException($"{methodInfo.Name} must return task<>");
                }
            }
            var name = feignClient.Name.GetValueOrDefault(serviceType.FullName);
            feignClient.SetName(name);
            if (feignClient.InterceptorType != null)
            {
                if (!feignClient.InterceptorType.GetInterfaces().Any(it => typeof(IRequestInterceptor) == it))
                {
                    throw new Exception($"{serviceType.FullName} must inherit from interface IRequestInterceptor");
                }
                // 将定义的拦截前写入到服务列表
                //services.AddTransient(feignClient.InterceptorType);
            }
            OpenFeign.IHttpClientFactory httpClientFactory = ServiceFactory.GetService<OpenFeign.IHttpClientFactory>();
            //忽略https证书
            if (feignClient.IsIgnoreHttpsCertificateValidate)
            {
                var httpClientHandler = new HttpClientHandler();
                httpClientHandler.ServerCertificateCustomValidationCallback += (sender, certificate, chain, errors) => true;
                var httpClient = new HttpClient(httpClientHandler);
                httpClientFactory.CreateClient(name, httpClient);
            }
            var serviceDescriptor = new ServiceDescriptor(serviceType, Factory);
            ServiceFactory.RegisterService(serviceType, Factory());
        }
    }
}
